package com.augurit.common.base.dao;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.springframework.util.Assert;
import org.springside.modules.orm.Page;
import org.springside.modules.orm.hibernate.HibernateDao;

/**
 * 基础DAO类
 */
public class BaseDao<T, PK extends Serializable> extends HibernateDao<T, PK>{
	
	/**
	 * 按HQL分页查询.
	 * @author 陈卫光
	 * @param page 分页参数.不支持其中的orderBy参数.
	 * @param hql hql语句.
	 * @param values 数量可变的查询参数,按顺序绑定.
	 * @return 分页查询结果, 附带结果列表及所有查询时的参数.
	 */
	@SuppressWarnings("unchecked")
	public Page<T> findPage(final Page<T> page, final String hql, final List values) {
		Assert.notNull(page, "page不能为空");

		if(values != null && values.size() > 0)
			return findPage(page, hql, values.toArray(new Object[values.size()]));
		else
			return findPage(page, hql);
	}
	
	/**
	 * 简单SQL查询  
	 * 
	 * @param sql
	 * @return
	 */
	public  List<Map> queryForList(String sql) {
		Connection conn = null;
		Statement st = null;
		ResultSet rs = null;
		List<Map> tempList = new ArrayList<Map>();
		try {
			long timeBefore = System.currentTimeMillis();
			conn = getSession().connection();
			st = conn.createStatement();
			rs = st.executeQuery(sql);
			ResultSetMetaData meta = rs.getMetaData();
			int columnCount = meta.getColumnCount();
			while(rs.next()) {
				Map<String, String> map = new LinkedHashMap<String, String>();
				for(int i=1; i<=columnCount; i++) {
					String colName = meta.getColumnLabel(i).toLowerCase();
					String colValue = rs.getString(i);
					map.put(colName, colValue);
				}
				tempList.add(map);
			}

		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			free(conn, st, rs);
		}
		
		return tempList;
	}
	
	/**  
	 * 关闭连接资源  
	 * @param conn  
	 */
	public static void free(Connection conn, Statement st, ResultSet rs) {
		if(rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(st != null) {
			try {
				st.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * 按HQL查询对象列表.
	 * @author 陈卫光
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public <X> List<X> find(final String hql, final List values) {
		return createQuery(hql, values).list();
	}
	
	/**
	 * 按HQL查询唯一对象.
	 * @author 陈卫光
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public <X> X findUnique(final String hql, final List values) {
		return (X) createQuery(hql, values).uniqueResult();
	}
	
	/**
	 * 根据查询HQL与参数列表创建Query对象.
	 * 本类封装的find()函数全部默认返回对象类型为T,当不为T时使用本函数.
	 * @author 陈卫光
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public Query createQuery(final String queryString, final List values) {
		if(values != null && values.size() > 0)
			return createQuery(queryString, values.toArray(new Object[values.size()]));
		else
			return createQuery(queryString);
	}
	
	/**
	 * 删除对象.
	 * @author 陈卫光
	 * @param entity 对象必须是session中的对象或含id属性的transient对象.
	 */
	public void delete(final List<T> entities) {
		Assert.notEmpty(entities, "entities不能为空");
		for(T entity : entities){
			getSession().delete(entity);
			logger.debug("delete entity: {}", entity);
		}
	}
	
	/**
	 * 按id集合删除多个对象.
	 * @author 陈卫光
	 * @param ids 主键或主键数组
	 */
	public void delete(final PK... ids) {
		Assert.notNull(ids, "ids不能为空");
		for(PK id : ids){
			delete(id);
			logger.debug("delete entity {},id is {}", entityClass.getSimpleName(), id);
		}
	}
	
	@SuppressWarnings("unchecked")
	public Page<T> findPageByScrollMode(final Page<T> page, final String hql, final Map<String, ?> values) {
		Assert.notNull(page, "page不能为空");

		Query q = createQuery(hql, values);

		ScrollableResults scrollableResults = q.scroll(ScrollMode.SCROLL_SENSITIVE);   
		scrollableResults.last();   
		page.setTotalCount(scrollableResults.getRowNumber() + 1);
		
		setPageParameter(q, page);

		List result = q.list();
		page.setResult(result);
		
		return page;
	}
}
